package cn.heyige.backend.facade;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

import cn.heyige.backend.entity.AdminDO;
import cn.heyige.backend.entity.UserDO;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.heyige.backend.common.RedisConstant;
import cn.heyige.backend.dto.AdminDto;
import cn.heyige.backend.dto.UserDTO;
import cn.heyige.backend.entity.UserQuotaDO;
import cn.heyige.backend.exception.BusinessException;
import cn.heyige.backend.exception.ErrorCode;
import cn.heyige.backend.mapper.AdminMapper;
import cn.heyige.backend.service.UserQuotaService;
import cn.heyige.backend.service.UserService;
import cn.heyige.backend.util.JwtUtil;
import cn.heyige.backend.util.RedisUtil;

import cn.hutool.crypto.digest.DigestUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserFacade {

    private final JwtUtil jwtUtil;
    private final UserService userService;
    private final UserQuotaService userQuotaService;
    private final AdminMapper adminMapper;

    public UserDTO.LoginResponse login(UserDTO.LoginRequest loginRequest) {
        String username = loginRequest.getUsername();
        String password = loginRequest.getPassword();

        LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDO::getUsername, username)
                .or()
                .eq(UserDO::getEmail, username)
                .or()
                .eq(UserDO::getPhone, username);

        UserDO userDO = userService.getOne(queryWrapper);
        if (userDO == null) {
            throw new BusinessException(ErrorCode.USER_NOT_FOUND);
        }
        if (!DigestUtil.bcryptCheck(password, userDO.getPassword())) {
            throw new BusinessException(ErrorCode.USER_PASSWORD_ERROR);
        }
        // 更新登录信息
        userDO.setLastLoginTime(LocalDateTime.now());
        userDO.setLoginCount(userDO.getLoginCount() + 1);
        userService.updateById(userDO);
        // 构建响应
        UserDTO.LoginResponse response = new UserDTO.LoginResponse();
        response.setToken(jwtUtil.generateAccessToken(userDO.getId(), userDO.getUsername()));
        response.setUserId(userDO.getId());
        response.setUsername(userDO.getUsername());
        response.setEmail(userDO.getEmail());
        response.setPhone(userDO.getPhone());
        response.setAvatar(userDO.getAvatar());
        return response;
    }

    public UserDO register(UserDTO.RegisterRequest registerRequest) {
        String username = registerRequest.getUsername();
        String email = registerRequest.getEmail();
        String phone = registerRequest.getPhone();
        String password = registerRequest.getPassword();
        // 检查用户名是否已存在
        LambdaQueryWrapper<UserDO> usernameQueryWrapper = new LambdaQueryWrapper<>();
        usernameQueryWrapper.eq(UserDO::getUsername, username);
        if (userService.getOne(usernameQueryWrapper) != null) {
            throw new BusinessException(ErrorCode.USER_NAME_ALREADY_EXISTS);
        }
        // 检查邮箱是否已存在
        if (email != null) {
            LambdaQueryWrapper<UserDO> emailQueryWrapper = new LambdaQueryWrapper<>();
            emailQueryWrapper.eq(UserDO::getEmail, email);
            if (userService.getOne(emailQueryWrapper) != null) {
                throw new BusinessException(ErrorCode.USER_EMAIL_EXISTS);
            }
        }
        // 检查手机号是否已存在
        if (phone != null) {
            LambdaQueryWrapper<UserDO> phoneQueryWrapper = new LambdaQueryWrapper<>();
            phoneQueryWrapper.eq(UserDO::getPhone, phone);
            if (userService.getOne(phoneQueryWrapper) != null) {
                throw new BusinessException(ErrorCode.USER_PHONE_EXISTS);
            }
        }
        // 创建用户
        UserDO userDO = new UserDO();
        userDO.setUsername(username);
        userDO.setEmail(email);
        userDO.setPhone(phone);
        userDO.setPassword(DigestUtil.bcrypt(password));
        userDO.setLoginCount(0);
        userDO.setCreateTime(LocalDateTime.now());
        userService.save(userDO);
        // 创建用户额度
        UserQuotaDO userQuotaDO = new UserQuotaDO();
        userQuotaDO.setUserId(userDO.getId());
        userQuotaService.save(userQuotaDO);
        log.info("用户注册成功: {}", username);
        return userDO;
    }


    public UserDO updateUser(Long userId, UserDTO userDto) {
        UserDO userDO = userService.getById(userId);

        if (userDto.getEmail() != null) {
            // 检查邮箱是否已被其他用户使用
            if (!userDO.getEmail().equals(userDto.getEmail())) {
                LambdaQueryWrapper<UserDO> emailQueryWrapper = new LambdaQueryWrapper<>();
                emailQueryWrapper.eq(UserDO::getEmail, userDto.getEmail());
                if (userService.getOne(emailQueryWrapper) != null) {
                    throw new BusinessException(ErrorCode.USER_EMAIL_EXISTS);
                }
            }
            userDO.setEmail(userDto.getEmail());
        }

        if (userDto.getPhone() != null) {
            // 检查手机号是否已被其他用户使用
            if (!userDO.getPhone().equals(userDto.getPhone())) {
                LambdaQueryWrapper<UserDO> phoneQueryWrapper = new LambdaQueryWrapper<>();
                phoneQueryWrapper.eq(UserDO::getPhone, userDto.getPhone());
                if (userService.getOne(phoneQueryWrapper) != null) {
                    throw new BusinessException(ErrorCode.USER_PHONE_EXISTS);
                }
            }
            userDO.setPhone(userDto.getPhone());
        }

        if (userDto.getAvatar() != null) {
            userDO.setAvatar(userDto.getAvatar());
        }

        userService.updateById(userDO);
        return userDO;
    }

    public void changePassword(Long userId, String oldPassword, String newPassword) {
        UserDO userDO = userService.getById(userId);


        if (!DigestUtil.bcryptCheck(oldPassword, userDO.getPassword())) {
            throw new BusinessException(ErrorCode.USER_PASSWORD_ERROR);
        }

        userDO.setPassword(DigestUtil.bcrypt(oldPassword));
        userService.updateById(userDO);

        log.info("用户修改密码成功: {}", userDO.getUsername());
    }

    public void bindWechat(Long userId, String wxOpenid) {
        UserDO userDO = userService.getById(userId);
        // 检查微信是否已被绑定
        LambdaQueryWrapper<UserDO> wxQueryWrapper = new LambdaQueryWrapper<>();
        wxQueryWrapper.eq(UserDO::getWxOpenid, wxOpenid);
        if (userService.getOne(wxQueryWrapper) != null) {
            throw new BusinessException(ErrorCode.WX_ALREADY_BIND);
        }
        userDO.setWxOpenid(wxOpenid);
        userService.updateById(userDO);
        log.info("用户绑定微信成功: {}", userDO.getUsername());
    }

    public UserDO getUserById(Long userId) {
        return userService.getById(userId);
    }

    public UserDO getUserByUsername(String username) {
        return userService.getOne(new LambdaQueryWrapper<UserDO>().eq(UserDO::getUsername, username));
    }

    public IPage<UserDO> getUserList(Integer page, Integer size) {
        Page<UserDO> userPage = new Page<>(page, size);
        return userService.page(userPage);
    }

    public AdminDto.LoginResponse adminLogin(UserDTO.LoginRequest loginRequest) {
        String username = loginRequest.getUsername();
        String password = loginRequest.getPassword();

        LambdaQueryWrapper<AdminDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AdminDO::getUsername, username)
                .or()
                .eq(AdminDO::getEmail, username)
                .or()
                .eq(AdminDO::getPhone, username);

        AdminDO adminDO = adminMapper.selectOne(queryWrapper);
        if (adminDO == null) {
            throw new BusinessException(ErrorCode.USER_NOT_FOUND);
        }
        if (!DigestUtil.bcryptCheck(password, adminDO.getPassword())) {
            throw new BusinessException(ErrorCode.USER_PASSWORD_ERROR);
        }
        // 构建响应
        AdminDto.LoginResponse response = new AdminDto.LoginResponse();
        response.setToken(jwtUtil.generateAccessToken(adminDO.getId(), adminDO.getUsername()));
        response.setUserId(adminDO.getId());
        response.setUsername(adminDO.getUsername());
        response.setEmail(adminDO.getEmail());
        response.setPhone(adminDO.getPhone());
        response.setAvatar(adminDO.getAvatar());
        return response;
    }

    public AdminDO adminRegister(UserDTO.RegisterRequest registerRequest) {
        String username = registerRequest.getUsername();
        String email = registerRequest.getEmail();
        String phone = registerRequest.getPhone();
        String password = registerRequest.getPassword();
        // 检查用户名是否已存在
        LambdaQueryWrapper<AdminDO> usernameQueryWrapper = new LambdaQueryWrapper<>();
        usernameQueryWrapper.eq(AdminDO::getUsername, username);
        if (adminMapper.selectOne(usernameQueryWrapper) != null) {
            throw new BusinessException(ErrorCode.USER_NAME_ALREADY_EXISTS);
        }
        // 检查邮箱是否已存在
        if (email != null) {
            LambdaQueryWrapper<AdminDO> emailQueryWrapper = new LambdaQueryWrapper<>();
            emailQueryWrapper.eq(AdminDO::getEmail, email);
            if (adminMapper.selectOne(emailQueryWrapper) != null) {
                throw new BusinessException(ErrorCode.USER_EMAIL_EXISTS);
            }
        }
        // 检查手机号是否已存在
        if (phone != null) {
            LambdaQueryWrapper<AdminDO> phoneQueryWrapper = new LambdaQueryWrapper<>();
            phoneQueryWrapper.eq(AdminDO::getPhone, phone);
            if (adminMapper.selectOne(phoneQueryWrapper) != null) {
                throw new BusinessException(ErrorCode.USER_PHONE_EXISTS);
            }
        }
        // 创建用户
        AdminDO adminDO = new AdminDO();
        adminDO.setUsername(username);
        adminDO.setEmail(email);
        adminDO.setPhone(phone);
        adminDO.setPassword(DigestUtil.bcrypt(password));
        adminDO.setCreateTime(LocalDateTime.now());
        adminMapper.insert(adminDO);
        log.info("管理员注册成功: {}", username);
        return adminDO;
    }

    /**
     * 用户退出登录
     * @param token JWT token
     */
    public void logoutUser(String token) {
        // 将token加入黑名单
        String key = RedisConstant.JWT_BLACKLIST_PREFIX + token;
        long expiration = jwtUtil.extractExpiration(token).getTime() - System.currentTimeMillis();
        if (expiration > 0) {
            RedisUtil.set(key, "blacklisted", expiration, TimeUnit.MILLISECONDS);
        }
        log.info("用户退出登录成功");
    }

    /**
     * 管理员退出登录
     * @param token JWT token
     */
    public void logoutAdmin(String token) {
        // 将token加入黑名单
        String key = RedisConstant.JWT_BLACKLIST_PREFIX + token;
        long expiration = jwtUtil.extractExpiration(token).getTime() - System.currentTimeMillis();
        if (expiration > 0) {
            RedisUtil.set(key, "blacklisted", expiration, TimeUnit.MILLISECONDS);
        }
        log.info("管理员退出登录成功");
    }

    /**
     * 获取管理员信息
     * @param adminId 管理员ID
     * @return 管理员信息
     */
    public AdminDO getAdminInfo(Long adminId) {
        return adminMapper.selectById(adminId);
    }
}